package itpenguin.review;

import itpenguin.common.PageInfo;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import net.sf.jsr107cache.Cache;
import net.sf.jsr107cache.CacheException;
import net.sf.jsr107cache.CacheFactory;
import net.sf.jsr107cache.CacheManager;

import com.google.appengine.api.memcache.jsr107cache.GCacheFactory;

/**
 * Cache controler
 * @author hiro
 *
 */
public class CacheFilter implements Filter {

	private static Cache cache;
	private static String sidebarCache;
	private static String mobileNavCache;
	
	@Override
	public void destroy() {
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		
		final StringWriter sw = new StringWriter();
		HttpServletResponse resp = (HttpServletResponse)response;
		HttpServletRequest req = (HttpServletRequest)request;
//		boolean isMobile = req.getHeader("User-Agent").matches(".*(iPhone|Android|Windows Phone).*");
		boolean isMobile = false;
		String cacheKey = isMobile ? "m@" + req.getRequestURI() : req.getRequestURI();
		
		req.setAttribute("isMobile", isMobile);
		resp.addDateHeader("Date", (new Date()).getTime());
		resp.addHeader("cache-control", "public, max-age=10000");		
		
		if (cache.containsKey(cacheKey)){
			PageInfo page = (PageInfo)cache.get(cacheKey);
			resp.setCharacterEncoding("UTF-8");
			resp.setHeader("Content-Type","text/html; charset=utf-8");
			resp.addDateHeader("Last-Modified", page.published);
			PrintWriter out = response.getWriter();
			out.write(page.content);
		} else {
			final LongHolder published = new LongHolder();
			ServletResponse wrapRes 
			= new HttpServletResponseWrapper(resp)
			{
	
				@Override
				public ServletOutputStream getOutputStream() throws IOException {
					return new ServletOutputStream() {
			            @Override
			            public void write(int b) throws IOException {
			            }
			        };
	
				}
	
				@Override
				public PrintWriter getWriter() throws IOException {
					 return new PrintWriter(sw);
				}

				@Override
				public void addDateHeader(String name, long date) {
					published.value = date;
				}
				
			};
			
			request.setAttribute("sidebarCache", isMobile ? mobileNavCache :sidebarCache);
			chain.doFilter(req, wrapRes);
			if (isMobile) {
				mobileNavCache = (String)request.getAttribute("sidebarCache");
			} else {
				sidebarCache = (String)request.getAttribute("sidebarCache");
			}
			
			if (!response.isCommitted()) {
				PageInfo page = new PageInfo();
				page.content = sw.toString();
				page.published = published.value;
				resp.addDateHeader("Last-Modified", published.value);
				cache.put(cacheKey, page); 
				PrintWriter out = response.getWriter();
				out.write(page.content);
			}
		}
		
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		Map<String, Object> props = new HashMap<String, Object>();
		props.put(GCacheFactory.EXPIRATION_DELTA, 43200);
		try {
			CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
			cache = cacheFactory.createCache(props);
		} catch (CacheException e) {
			throw new ServletException(e);
		}
	}
	
	private class LongHolder
	{
		public long value;
	}
	
	public static void clearCache(String id) {
		sidebarCache = null;
		mobileNavCache = null;
		cache.remove(id);
	}

	public static void clearCache(ServletContext sc) {
		mobileNavCache = null;
		sidebarCache = null;
		cache.clear();
	}
}
